package sjtu.ist.warehouse4ws.dao;



import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.List;

import org.apache.derby.iapi.store.raw.Page;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class BaseDaoHibernate<T> extends HibernateDaoSupport implements BaseDao<T>{
	protected Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass()
			.getGenericSuperclass()).getActualTypeArguments()[0];
	
	public void delete(Long id) {
		T obj = this.load(id);
		getHibernateTemplate().delete(obj);
	}

	public T get(Long id) {
		return (T) getHibernateTemplate().get(entityClass, id);
	}

	public Serializable save(T obj) {
		getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_EAGER); 
		return (Long) getHibernateTemplate().save(obj);
	}

	public void update(T obj) {
		getHibernateTemplate().update(obj);
	}

	public void delete(T obj) {
		getHibernateTemplate().delete(obj);
	}

	public T merge(T obj) {
		return (T)getHibernateTemplate().merge(obj);
	}

	public T load(Long id) {
		return (T) getHibernateTemplate().load(entityClass, id);
	}

	public List<T> loadAll() {
		return getHibernateTemplate().loadAll(entityClass);
	}

	public int countByCriteria(final DetachedCriteria detachedCriteria) {
		Long count = (Long) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Long doInHibernate(Session session)
							throws HibernateException {
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						return (Long)criteria.setProjection(Projections.rowCount())
								.uniqueResult();
					}
				});
		return count.intValue();
	}

	public List<T> findByCriteria(DetachedCriteria detachedCriteria) {
		return getHibernateTemplate().findByCriteria(detachedCriteria);
	}

	public List<T> findByCriteria(DetachedCriteria detachedCriteria, int first,
			int max) {
		return getHibernateTemplate().findByCriteria(detachedCriteria, first,
				max);
	}

	public List<T> findByExample(T obj) {
		return getHibernateTemplate().findByExample(obj);
	}

	public List<T> findByHql(String hql, Object[] params) {
		Query query = getHibernateSession().createQuery(hql);
		if (null != params && params.length > 0) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query.list();
	}

	public Session getHibernateSession() {
		return SessionFactoryUtils.getSession(getHibernateTemplate()
				.getSessionFactory(), false);
	}

	@Override
	public int updateByHql(String hql, Object[] params) {
		Query query = getHibernateSession().createQuery(hql);
		if (null != params && params.length > 0) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query.executeUpdate();
	}
	
	@Override
	public int updateBySql(String sql, Object[] params) {
		Query query = getHibernateSession().createSQLQuery(sql);
		if (null != params && params.length > 0) {
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
		}
		return query.executeUpdate();
	}

	@Override
	public int updateColumns(Long id, String[] columns, Object[] params) {
		if (null != columns && columns.length > 0 && null != params
				&& columns.length == params.length) {
			StringBuilder sb = new StringBuilder();
			sb.append("update ").append(entityClass.getName()).append(" set ");
			for (int i = 0; i < columns.length; i++) {
				sb.append(columns[i]).append("=?");
				if (i < columns.length - 1) {
					sb.append(",");
				}
			}
			sb.append(" where id=?");
			Query query = getHibernateSession().createQuery(sb.toString());
			for (int i = 0; i < params.length; i++) {
				query.setParameter(i, params[i]);
			}
			query.setParameter(columns.length, id);
			return query.executeUpdate();
		}
		return -1;
	}

	/*
	@SuppressWarnings("unchecked")
	@Override
	public Page findPageByCreiteria(int pno, int pageSize, final DetachedCriteria detachedCriteria) {
		// TODO Auto-generated method stub
		final int startIndex=(pno-1)*pageSize;
		final int size=pageSize;
		final int pageNo=pno;
		return(Page) getHibernateTemplate().execute(new HibernateCallback(){
            public Object doInHibernate(Session session)throws HibernateException {
                    Criteria criteria = detachedCriteria.getExecutableCriteria(session);
                    long totalCount=criteria.list().size();
                    List items = criteria.setFirstResult(startIndex).setMaxResults(size).list();

                    Page ps = new Page(size,pageNo,totalCount,items);
                    return ps; 
            }
    }); 
	}	
	*/
	
	
	
	/**
	 * 使用hql语句进行分页查询
	 * @param hql 需要查询的hql语句
	 * @param offset 第一条记录索引
	 * @param pageSize 每页需要显示的记录数
	 * @return 当前页的所有记录
	 */
	public List findByPage(final String hql, 
		final int offset, final int pageSize)
	{
		
		//通过一个HibernateCallback对象来执行查询
		List list = getHibernateTemplate()
			.executeFind(new HibernateCallback()
		{
			//实现HibernateCallback接口必须实现的方法
			public Object doInHibernate(Session session)
				throws HibernateException, SQLException
			{
				//执行Hibernate分页查询
				List result = session.createQuery(hql)
					.setFirstResult(offset)
					.setMaxResults(pageSize)
					.list();
				return result;
			}
		});
		return list;
	}

	/**
	 * 使用hql语句进行分页查询
	 * @param hql 需要查询的hql语句
	 * @param value 如果hql有一个参数需要传入，value就是传入hql语句的参数
	 * @param offset 第一条记录索引
	 * @param pageSize 每页需要显示的记录数
	 * @return 当前页的所有记录
	 */
	public List findByPage(final String hql , final Object value ,
		final int offset, final int pageSize)
	{
		//通过一个HibernateCallback对象来执行查询
		List list = getHibernateTemplate()
			.executeFind(new HibernateCallback()
		{
			//实现HibernateCallback接口必须实现的方法
			public Object doInHibernate(Session session)
				throws HibernateException, SQLException
			{
				//执行Hibernate分页查询
				List result = session.createQuery(hql)
					//为hql语句传入参数
					.setParameter(0, value) 
					.setFirstResult(offset)
					.setMaxResults(pageSize)
					.list();
				return result;
			}
		});
		return list;
	}

	/**
	 * 使用hql语句进行分页查询
	 * @param hql 需要查询的hql语句
	 * @param values 如果hql有多个个参数需要传入，values就是传入hql的参数数组
	 * @param offset 第一条记录索引
	 * @param pageSize 每页需要显示的记录数
	 * @return 当前页的所有记录
	 */
	public List findByPage(final String hql, final Object[] values,
		final int offset, final int pageSize)
	{		
		//通过一个HibernateCallback对象来执行查询
		List list = getHibernateTemplate()
			.executeFind(new HibernateCallback()
		{
			//实现HibernateCallback接口必须实现的方法
			public Object doInHibernate(Session session)
				throws HibernateException, SQLException
			{
				//执行Hibernate分页查询
				Query query = session.createQuery(hql);
				//为hql语句传入参数
				for (int i = 0 ; i < values.length ; i++)
				{
					query.setParameter( i, values[i]);
				}
				List result = query.setFirstResult(offset)
					.setMaxResults(pageSize)
					.list();
				return result;
			}
		});
		return list;
	}
}
